//
//  HYQUploadImagesManager.m
//  HYQPhotoUploader
//
//  Created by __无邪_ on 2018/8/24.
//  Copyright © 2018 __无邪_. All rights reserved.
//

#import "HYQUploadImagesManager.h"
#import <CoreImage/CoreImage.h>
#import <ImageIO/ImageIO.h>
#import "UpYunBlockUpLoader.h" //分块上传，适合大文件上传、移动端、弱网情况下使用
#import <CommonCrypto/CommonCrypto.h>
#import <AdSupport/ASIdentifierManager.h>

@interface HYQUploadImagesManager ()
@property(nonatomic)int64_t totalBytesCount;
@property(nonatomic)int64_t completedBytesCount;
@property(nonatomic,strong)NSMutableArray *results;
@property(nonatomic,strong)NSMutableArray *completedBytes;
@end

@implementation HYQUploadImagesManager{
    PHCachingImageManager *_phCachingImageManager;
}


+ (instancetype)sharedManager {
    static HYQUploadImagesManager *manager;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [HYQUploadImagesManager.alloc init];

    });
    return manager;
}

- (instancetype)init
{
    if (self = [super init]) {
        _configurer = [HYQUploaderConfig new];
        _results = [NSMutableArray.alloc init];
        _completedBytes = [NSMutableArray.alloc init];
    }
    return self;
}

//分块上传

- (void)uploadByFilePaths:(NSArray <NSString *>*)filePaths completed:(HYQUploaderResponseHandler)completed progress:(HYQUpLoaderProgressBlock)progress{
    [self clear];
    
    for (int i = 0; i < filePaths.count; i++) {
        NSString *filePath = filePaths[i];
        int64_t bytes = [self fileSize:filePath];
        CGSize size = [self imageSize:filePath];
        
        self.totalBytesCount += bytes;
        
        NSMutableDictionary *fileInfo = [NSMutableDictionary.alloc init];
        [fileInfo setObject:@(size.width) forKey:@"width"];
        [fileInfo setObject:@(size.height) forKey:@"height"];
        [fileInfo setObject:@(bytes) forKey:@"bytes"];
        [fileInfo setObject:filePath forKey:@"path"];
        [self.results addObject:fileInfo];
        [self.completedBytes addObject:@0];
    }
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    __block NSString *errMessage = nil;
    
    for (int i = 0; i < filePaths.count; i++) {
        dispatch_group_enter(group);
        NSString *filePath = filePaths[i];
        
        [self uploadFileWithPath:filePath success:^(NSString *target) {
            NSMutableDictionary *info = self.results[i];
            [info setObject:target forKey:@"url"];
            dispatch_group_leave(group);
        } failure:^(NSString *errMsg) {
            errMessage = errMsg;
            dispatch_group_leave(group);
        } progress:^(int64_t completedBytesCount, int64_t totalBytesCount) {
            [self.completedBytes replaceObjectAtIndex:i withObject:@(completedBytesCount)];
            if (progress) {
                progress(self.completedBytesCount,self.totalBytesCount);
            }
        }];
    }
    
    dispatch_group_notify(group, queue, ^{
        if (completed) {
            completed(errMessage,[self.results copy]);
        }
    });
    
}
- (void)uploadByImages:(NSArray <UIImage *>*)images completed:(HYQUploaderResponseHandler)completed progress:(HYQUpLoaderProgressBlock)progress {
    
    NSMutableArray *filePaths = [NSMutableArray.alloc init];
    for (int i = 0; i < images.count; i++) {
        UIImage *image  = images[i];
        NSString *filePath = [HYQUploadImagesManager filePathWithImage:image];
        [filePaths addObject:filePath];
    }
    
    [self uploadByFilePaths:filePaths completed:completed progress:progress];
    
}

- (void)uploadByPHAssets:(NSArray <PHAsset *>*)assets original:(BOOL)original completed:(HYQUploaderResponseHandler)completed progress:(HYQUpLoaderProgressBlock)progress {
    
    NSMutableArray *images = [NSMutableArray.alloc init];
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    __block NSString *errMessage = nil;
    for (int i = 0; i < assets.count; i++) {
        dispatch_group_enter(group);
        [self requestImageWithPHAsset:assets[i] highQuality:original completion:^(UIImage *result, NSDictionary<NSString *,id> *info) {
            [images addObject:result];
            dispatch_group_leave(group);
        } progressHandler:^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) {
            if (error) {
                errMessage = error.localizedDescription;
                dispatch_group_leave(group);
            }
        }];
    }
    
    dispatch_group_notify(group, queue, ^{
        if (errMessage) {
            completed(errMessage, nil);
        }else{
            [self uploadByImages:images completed:completed progress:progress];
        }
    });
    
}


- (void)uploadFileWithPath:(NSString *)filePath success:(void (^)(NSString *target))successBlock failure:(void (^)(NSString *errorMsg))failureBlock progress:(HYQUpLoaderProgressBlock)progressBlock {
    // 不同的上传任务要创建不同的loader对象
    NSString *savePath = [self fileUniqueNameWithPath:filePath];
    UpYunBlockUpLoader *upLoader = [UpYunBlockUpLoader.alloc init];
    [upLoader uploadWithBucketName:self.configurer.bucketName operator:self.configurer.userName password:self.configurer.password filePath:filePath savePath:savePath success:^(NSHTTPURLResponse *response, NSDictionary *responseBody) {
        successBlock(savePath);
    } failure:^(NSError *error, NSHTTPURLResponse *response, NSDictionary *responseBody) {
        NSLog(@"上传失败 error：%@", error);
        NSLog(@"上传失败 code=%ld, responseHeader：%@", (long)response.statusCode, response.allHeaderFields);
        NSLog(@"上传失败 message：%@", responseBody);
        failureBlock(error.localizedDescription);
    } progress:progressBlock];
}

- (void)cancel {
    //TODO
}

+ (void)clearCache {
    [UpYunBlockUpLoader clearCache];
    NSString *tmpDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"/HYQUploader/"];
    [[NSFileManager defaultManager] removeItemAtPath:tmpDir error:nil];
}

#pragma mark - private

- (NSInteger)requestImageWithPHAsset:(PHAsset *)asset highQuality:(BOOL)highQuality completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion progressHandler:(PHAssetImageProgressHandler)phProgressHandler {
    PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
    //synchronous：指定请求是否同步执行。
    //resizeMode：对请求的图像怎样缩放。有三种选择：None，不缩放；Fast，尽快地提供接近或稍微大于要求的尺寸；Exact，精准提供要求的尺寸。
    //deliveryMode：图像质量。有三种值：Opportunistic，在速度与质量中均衡；HighQualityFormat，不管花费多长时间，提供高质量图像；FastFormat，以最快速度提供好的质量。
    //这个属性只有在 synchronous 为 true 时有效。
    imageRequestOptions.networkAccessAllowed = YES; // 允许访问网络
    imageRequestOptions.progressHandler = phProgressHandler;
    
    
    CGSize targetSize = PHImageManagerMaximumSize;
    PHImageContentMode contentMode = PHImageContentModeDefault;
    if (!highQuality) {
        imageRequestOptions.synchronous = YES;
        imageRequestOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
        imageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
        targetSize = CGSizeMake(414 * 2, 736 * 2);
        contentMode = PHImageContentModeAspectFill;
    }
    
    return [[self phCachingImageManager] requestImageForAsset:asset targetSize:targetSize contentMode:contentMode options:imageRequestOptions resultHandler:^(UIImage *result, NSDictionary *info) {
        if (completion) {
            completion(result, info);
        }
    }];
}

+ (NSString *)filePathWithImage:(UIImage *)image {
    NSData *imageData = UIImageJPEGRepresentation(image,1);
    if (imageData.length / 1024 > 1024) {
        imageData = UIImageJPEGRepresentation(image, 0.7);
    }
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *tmpDir = [NSTemporaryDirectory() stringByAppendingPathComponent:@"/HYQUploader/"];
    
    NSString *filePath = [NSString stringWithFormat:@"%@/%@.jpg",tmpDir,@([[NSDate date] timeIntervalSince1970])];
    [fileManager createDirectoryAtPath:tmpDir withIntermediateDirectories:NO attributes:nil error:nil];
    [fileManager createFileAtPath:filePath contents:imageData attributes:nil];
    
    return filePath;
}

- (void)clear {
    // 我们不使用断点续传功能
    [UpYunBlockUpLoader clearCache];
    [self.results removeAllObjects];
    [self.completedBytes removeAllObjects];
    [self setTotalBytesCount:0];
}
- (NSString *)fileUniqueNameWithPath:(NSString *)filePath {
    // 从路径中获得完整的文件名（带后缀）
    NSString *name = [filePath pathExtension];
    
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    formatter.dateFormat = @"yyyyMMdd";
    NSDate *nowDate = [NSDate date];
    
    NSString *pathStr = [formatter stringFromDate:nowDate];
    NSString *uniqueName = [NSString stringWithFormat:@"%.0f%@",[nowDate timeIntervalSince1970] * 1000, [self idfa]];
    NSString *md5Str = [self md5StringWithOriginStr:uniqueName];
    return [NSString stringWithFormat:@"/%@/%@.%@",pathStr, md5Str, name];
}

- (NSString *)idfa
{
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

- (NSString *)md5StringWithOriginStr:(NSString *)str
{
    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(data.bytes,(CC_LONG)data.length, result);
    return [NSString stringWithFormat:
            @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
            result[0], result[1], result[2], result[3],
            result[4], result[5], result[6], result[7],
            result[8], result[9], result[10], result[11],
            result[12], result[13], result[14], result[15]
            ];
}

- (int64_t)completedBytesCount {
    NSNumber *num = [self.completedBytes valueForKeyPath:@"@sum.self"];
    return num.longLongValue;
}
- (CGSize)imageSize:(NSString *)path {
    
    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:path],NULL);
    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0,NULL);
    NSNumber *pixelWidthObj = (__bridge NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
    NSNumber *pixelHeightObj = (__bridge NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
    NSInteger orientation = [(__bridge NSNumber *)CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation) integerValue];
    NSNumber *temp = @0;
    switch (orientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationRight:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored: {
            temp = pixelWidthObj;
            pixelWidthObj = pixelHeightObj;
            pixelHeightObj = temp;
            break;
        }
        default:
            break;
    }
    CFRelease(imageProperties);
    CFRelease(imageSourceRef);
    return CGSizeMake(pixelWidthObj.floatValue, pixelHeightObj.floatValue);
}
- (int64_t)fileSize:(NSString *)path {
    NSFileManager *fileManager = [[NSFileManager alloc] init];
    if([fileManager fileExistsAtPath:path]){
        NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:nil];
        NSNumber *num = [attributes objectForKey:NSFileSize];
        return num.longLongValue;
    }
    return 0;
}

#pragma mark -

- (PHCachingImageManager *)phCachingImageManager {
    if (!_phCachingImageManager) {
        _phCachingImageManager = [[PHCachingImageManager alloc] init];
    }
    return _phCachingImageManager;
}



@end
